package com.example.chatapp.websocket;

import com.example.chatapp.model.MessageEntity;
import com.example.chatapp.model.ResultMessage;
import com.example.chatapp.redis.RedisMessagePublisher;
import com.example.chatapp.service.ChatService;
import com.example.chatapp.service.SeqService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.util.Map;

/**
 *
 * 负责接收客户端消息、分配 seq、持久化、push 最近消息 list、发布到 Redis channel（分布式广播）
 */
@Component
public class ChatWebSocketHandler implements WebSocketHandler {
    private final WebSocketSessionManager sessionManager;
    private final RedisMessagePublisher publisher;
    private final ChatService chatService;
    private final SeqService seqService;
    private final ObjectMapper mapper = new ObjectMapper();

    public ChatWebSocketHandler(WebSocketSessionManager sessionManager, RedisMessagePublisher publisher,
                                ChatService chatService, SeqService seqService) {
        this.sessionManager = sessionManager;
        this.publisher = publisher;
        this.chatService = chatService;
        this.seqService = seqService;
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        // 从 HTTP session（Spring Session 存储于 Redis）中读取 username 和 roomId
        Map<String, Object> attrs = session.getAttributes();
        String username = (String) attrs.getOrDefault("username", "guest");
        String roomId = (String) attrs.getOrDefault("roomId", "default");

        sessionManager.add(session, username, roomId);
        
        // ✅ 确保订阅该房间的 Redis 频道
        chatService.ensureRoomSubscribed(roomId);
        System.out.println("[ChatWebSocketHandler] User " + username + " connected to room: " + roomId);

        // 可选： 发送系统 join 消息（由服务端生成 seq 并发布）
        long seq = seqService.nextSeq(roomId);
        ResultMessage sys = new ResultMessage();
        sys.setRoomId(roomId);
        sys.setSeq(seq);
        sys.setSystem(true);
        sys.setFromName("system");
        sys.setMessage(username + " joined");
        sys.setTs(System.currentTimeMillis());

        String json = mapper.writeValueAsString(sys);
        // persist & cache & publish
        chatService.saveMessage(roomId, seq, "system", null, json, true);
        chatService.cacheRecentMessage(roomId, json); // ✅ 推送到 Redis 列表
        // publish to redis channel for distributed broadcast
        publisher.publish("chat:channel:" + roomId, json);
        System.out.println("[ChatWebSocketHandler] Published join message for " + username);
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        if (!(message instanceof TextMessage)) return;
        String payload = ((TextMessage) message).getPayload();

        // Expect client to send JSON like {type:'chat', roomId:'r1', toUser:'bob', content:'...'}
        Map<String, Object> map = mapper.readValue(payload, Map.class);
        String roomId = (String) map.getOrDefault("roomId", "default");
        String from = (String) session.getAttributes().getOrDefault("username", "guest");
        String toUserRaw = (String) map.get("toUser");
        String toUser = (toUserRaw == null || toUserRaw.trim().isEmpty()) ? null : toUserRaw.trim();
        Object contentObj = map.get("content");
        String content = contentObj != null ? contentObj.toString() : "";

        // assign seq for this room
        long seq = seqService.nextSeq(roomId);
        System.out.println("[ChatWebSocketHandler] Message from " + from + " in room " + roomId + ", seq=" + seq + ", content: " + content);

        // build ResultMessage to broadcast
        ResultMessage out = new ResultMessage();
        out.setRoomId(roomId);
        out.setSeq(seq);
        out.setSystem(false);
        out.setFromName(from);
        out.setToUser(toUser);
        out.setMessage(content);
        out.setTs(System.currentTimeMillis());

        String outJson = mapper.writeValueAsString(out);

        // persist to DB + push recent to redis
        chatService.saveMessage(roomId, seq, from, toUser, outJson, false);
        chatService.cacheRecentMessage(roomId, outJson);

        // publish to redis channel (distributed)
        publisher.publish("chat:channel:" + roomId, outJson);
        System.out.println("[ChatWebSocketHandler] Published message to Redis channel: chat:channel:" + roomId);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        session.close(CloseStatus.SERVER_ERROR);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        // remove from manager
        String username = (String) session.getAttributes().get("username");
        String roomId = (String) session.getAttributes().getOrDefault("roomId", "default");
        sessionManager.remove(session);
        System.out.println("[ChatWebSocketHandler] User " + username + " disconnected from room: " + roomId);

        long seq = seqService.nextSeq(roomId);
        ResultMessage sys = new ResultMessage();
        sys.setRoomId(roomId);
        sys.setSeq(seq);
        sys.setSystem(true);
        sys.setFromName("system");
        sys.setMessage(username + " left");
        sys.setTs(System.currentTimeMillis());

        String json = mapper.writeValueAsString(sys);
        chatService.saveMessage(roomId, seq, "system", null, json, true);
        chatService.cacheRecentMessage(roomId, json); // ✅ 推送到 Redis 列表
        publisher.publish("chat:channel:" + roomId, json);
    }

    @Override
    public boolean supportsPartialMessages() { return false; }
}
